﻿namespace Trader.Runner
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Windows;
    using System.Windows.Input;
    using System.Windows.Media;
    using Analyzing;
    using BO;
    using BO.Interface;
    using DataServices.Interface;
    using Indicators.Interface;
    using Indicators.TechnicalAnalysis;
    using Properties;
    using Swordfish.WPF.Charts;
    using Trading;
    using Trading.Interface;

//    using Trader.DataServices.Interface;
//    using Trader.Crawling;

    ///<summary>
    ///Interaction logic for Window1.xaml
    ///</summary>
    public partial class Window1 : Window
    {
        private static DateTime startDate;
        private readonly TradeDecider decider;
        private readonly BackgroundWorker traderWorker;
        private CommissionCharger commissionCharger;
        private List<IPortfolioState> portfolioStates;

        public Window1()
        {
            InitializeComponent();

            traderWorker = new BackgroundWorker();
            traderWorker.DoWork += worker_DoWork;
            traderWorker.ProgressChanged += traderWorker_ProgressChanged;
            traderWorker.RunWorkerCompleted += traderWorker_RunWorkerCompleted;
            traderWorker.WorkerSupportsCancellation = true;

            traderWorker.WorkerReportsProgress = true;

            stocksListView.SelectAll();

            signalsList.SelectAll();

            Closed += ((sender, e) => Settings.Default.Save());

            xyLineChartValue.UserRequestedX += xyLineChart_UserRequestedX;
            xyLineChartValue.SubNotes =
                new[]
                    {
                        "The value is shown after commission has been charged",
                        "To view portfolio state in specific date double click on the day in the chart"
                    };

            // Futer google search...
            //  Crawl crawl = new Crawl((IDataProvider)Resources["dataProvider"]);
            //   crawl.webConnect();
            decider = new TradeDecider(((IDataProvider) Resources["dataProvider"]).SignalsCache);
        }

        private void xyLineChart_UserRequestedX(int day)
        {
            if (portfolioStates == null)
            {
                return;
            }
            day = Math.Max(0, day);
            day = Math.Min(portfolioStates.Count - 1, day);
            portfolioStatesListView.Items.Clear();
            DateTime date = startDate + TimeSpan.FromDays(day);
            foreach (IPortfolioMember member in portfolioStates[day].PortfolioMembers)
            {
                portfolioStatesListView.Items.Add(new ViewableMember(member, date));
            }

            portfolioStatesListView.Items.Add(portfolioStates[day].Cash);
        }

        private void traderWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (!e.Cancelled)
            {
                tabControl.SelectedIndex = 1;
                var portfolio = (IPortfolio) e.Result;
                var valueLine = new ChartPrimitive {Label = "Value", Color = Colors.DarkBlue};
                var commisionsLine = new ChartPrimitive {Label = "Commissions", Color = Colors.DarkGreen};

                xyLineChartValue.Primitives.Clear();
                xyLineChartCommissions.Primitives.Clear();

                xyLineChartValue.Primitives.Add(valueLine);
                xyLineChartCommissions.Primitives.Add(commisionsLine);

                portfolioStates = new List<IPortfolioState>();

                DateTime fromDate = DateTime.ParseExact(fromDateTextBox.Text, "d/M/yyyy", null);
                DateTime toDate = DateTime.ParseExact(toDateTextBox.Text, "d/M/yyyy", null);
                var currecny = (ICurrecny) currencySelector.SelectedValue;
                var totalCommissions = new Money(0, currecny);
                for (DateTime date = fromDate; date <= toDate; date += TimeSpan.FromDays(1))
                {
                    IPortfolioState portfolioState = portfolio[date];
                    portfolioStates.Add(portfolioState);
                    double dayIndex = (date - fromDate).TotalDays;
                    valueLine.AddPoint(dayIndex, (double) portfolioState.GetValue(date).In(currecny, date));
                    if (commissionCharger[date] != null)
                    {
                        totalCommissions.Add(commissionCharger[date], date);
                    }
                    commisionsLine.AddPoint(dayIndex, (double) totalCommissions.In(currecny, date));
                }

                xyLineChartValue.RedrawPlotLines();
                xyLineChartCommissions.RedrawPlotLines();
            }
            HideProgress();
        }

        private void HideProgress()
        {
            progressBar.Visibility = Visibility.Hidden;
            stateLabel.Visibility = Visibility.Hidden;
            stopTraderButton.Visibility = Visibility.Hidden;
            tradeButton.Visibility = Visibility.Visible;
        }

        private void tradeButton_Click(object sender, RoutedEventArgs e)
        {
            DateTime result;
            if (!DateTime.TryParseExact(fromDateTextBox.Text, "d/M/yyyy", null, DateTimeStyles.None, out result))
            {
                MessageBox.Show("Please make sure 'From Date' is in format dd/MM/yyyy");
                return;
            }
            if (!DateTime.TryParseExact(toDateTextBox.Text, "d/M/yyyy", null, DateTimeStyles.None, out result))
            {
                MessageBox.Show("Please make sure 'To Date' is in format dd/MM/yyyy");
                return;
            }

            decimal testNumber;
            if (!decimal.TryParse(valueTextBox.Text, out testNumber))
            {
                MessageBox.Show("Please make sure Cash is a legal number (digits only)");
                return;
            }

            if (!decimal.TryParse(commissionTextBox.Text, out testNumber))
            {
                MessageBox.Show("Please make sure Commission is a legal number (digits only)");
                return;
            }

            if (!decimal.TryParse(interestTextBox.Text, out testNumber))
            {
                MessageBox.Show("Please make sure Interest is a legal number (digits only)");
                return;
            }

            double maxRisk;
            if (!double.TryParse(riskTextBox.Text, out maxRisk) || maxRisk < 0 || maxRisk > 1)
            {
                MessageBox.Show("Please make sure risk is a legal number (digits only) between 0 and 1");
                return;
            }

            progressBar.Visibility = Visibility.Visible;
            stateLabel.Visibility = Visibility.Visible;
            tradeButton.Visibility = Visibility.Hidden;
            stopTraderButton.Visibility = Visibility.Visible;
            progressBar.Value = 0;

            xyLineChartValue.YAxisLabel =
                string.Format("Portfolio value ({0})", ((ICurrecny) currencySelector.SelectedItem).Sign);

            xyLineChartCommissions.YAxisLabel =
                string.Format("Commissions chraged ({0})", ((ICurrecny) currencySelector.SelectedItem).Sign);

            startDate = DateTime.ParseExact(fromDateTextBox.Text, "d/M/yyyy", null);
            var tradeParams = new TradeParams
                                  {
                                      FromDate = startDate,
                                      ToDate = DateTime.ParseExact(toDateTextBox.Text, "d/M/yyyy", null),
                                      Money = new Money(
                                          decimal.Parse(valueTextBox.Text), (ICurrecny) currencySelector.SelectedItem),
                                      Stocks = stocksListView.SelectedItems.Cast<IStock>().ToList(),
                                      Commission = decimal.Parse(commissionTextBox.Text),
                                      NoRiskYearlyYield = decimal.Parse(interestTextBox.Text),
                                      MaxRisk = maxRisk,
                                      Signals = signalsList.SelectedItems.Cast<ISignal>().ToList()
                                  };
            traderWorker.RunWorkerAsync(tradeParams);
        }

        private void traderWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            var state = (string) e.UserState;
            stateLabel.Content = state;
            progressBar.Value = e.ProgressPercentage;
        }

        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            var tradeParams = (TradeParams) e.Argument;
            commissionCharger = new CommissionCharger(tradeParams.Commission);
            var riskChecker = new MaxDownChangeRiskChecker(tradeParams.MaxRisk);
            IPortfolio portfolio = decider.Trade(
                tradeParams.Money, tradeParams.Stocks, tradeParams.FromDate,
                tradeParams.ToDate, commissionCharger, traderWorker,
                tradeParams.NoRiskYearlyYield, riskChecker, tradeParams.Signals);
            if (portfolio == null)
            {
                e.Cancel = true;
            }
            else
            {
                e.Result = portfolio;
            }
        }

        private void selectAllButton_Click(object sender, RoutedEventArgs e)
        {
            stocksListView.SelectAll();
        }

        private void clearButton_Click(object sender, RoutedEventArgs e)
        {
            stocksListView.UnselectAll();
        }

        private void stopTraderButton_Click(object sender, RoutedEventArgs e)
        {
            traderWorker.CancelAsync();
            stopTraderButton.Visibility = Visibility.Hidden;
            progressBar.Visibility = Visibility.Hidden;
            stateLabel.Content = "Cancelling";
        }

        private void portfolioStatesListView_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (!(portfolioStatesListView.SelectedItem is ViewableMember))
            {
                return;
            }

            IPortfolioMember portfolioMember = ((ViewableMember) portfolioStatesListView.SelectedItem).Member;
            new SingleStock(portfolioMember.Stock, portfolioMember.Recommendation.Signal, portfolioMember.BuyDate,
                            portfolioMember.SellDate.Value).Show();
        }

        #region Nested type: TradeParams

        private class TradeParams
        {
            public decimal Commission;
            public DateTime FromDate;
            public double MaxRisk;
            public IMoney Money;
            public decimal NoRiskYearlyYield;
            public IList<IStock> Stocks;
            public DateTime ToDate;
            public IList<ISignal> Signals;
        }

        #endregion

        #region Nested type: ViewableMember

        private class ViewableMember
        {
            private readonly DateTime date;
            private readonly IPortfolioMember member;

            public ViewableMember(IPortfolioMember member, DateTime date)
            {
                this.member = member;
                this.date = date;
            }

            public IPortfolioMember Member
            {
                get { return member; }
            }

            public override string ToString()
            {
                return string.Format("{0}, {1} Units with total value of {2}", member.Stock, member.Units(date),
                                     member.CalculateValue(date));
            }
        }

        #endregion

        private void SelectAllSignals_Click(object sender, RoutedEventArgs e)
        {
            signalsList.SelectAll();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            signalsList.UnselectAll();
        }
    }
}